import { CMEVENTS, EventsRes, MouseStyle, PickerState } from '@amcax/base';
import { Picker3D, PickerMgr } from '@amcax/renderer';
import { BaseEventCenter } from '@app-base/common/events/BaseEventCenter';
import { userEvents } from '@app-base/module';
import { documentManager } from '@app-nextmesh/manager';
import {
  ModelEventType,
  ModelPickEvent,
  ModelTheme,
} from '@app-nextmesh/types';
import { events } from '@app-nextmesh/utils';
import {
  clearSelectedMeshes,
  getAllSelectedMeshesId,
  handleSelect,
  selectMeshes,
} from '@app-nextmesh/utils/picker';
import { isEqual } from 'lodash';

export type MouseInfo = {
  x: number;
  y: number;
};

export type Button = {
  onLeft: boolean;
  onMiddle: boolean;
  onRight: boolean;
  buttonDown: boolean;
};
export enum STATE {
  DEFAULT = 'default', // 建模
  SLEEPING = 'sleeping', // 禁用状态
}
export const pickSetting = {
  0: { point: true },
  1: { line: true },
  2: { face: true },
  3: { model: true },
  4: { all: true },
};

/* 事件模块 */
export class EventCenter extends BaseEventCenter {
  id: string = 'nextmesh';
  private _pickType: number[] = [4]; // 拾取类型（点、线、面、体、智能）
  idsMap: Map<number, number>;
  static instance: EventCenter;
  private currentModelTheme = ModelTheme.Default;
  picker: Picker3D = PickerMgr.getPicker<Picker3D>('3d');
  editingGroup: boolean;
  threshold: number = null;
  // 用于记录鼠标右键按下后，是否拖动了；没拖动才显示右键菜单
  private isMouseRightMoving = false;
  private rightButtonDownMouse?: MouseInfo;
  // 在ToolBar上切换拾取模式: 几何 | 网格
  private _pickMode: 'geometry' | 'mesh' = 'geometry';

  getEventRes<T extends MouseEvent | PointerEvent | KeyboardEvent>(
    event: T,
    eventName: string,
  ): EventsRes<T> {
    return {
      ...super.getEventRes(event, eventName),
      idsMap: this.idsMap,
    };
  }
  // 设置拾取阈值
  setThreshold(threshold: number) {
    this.threshold = threshold;
    return this;
  }

  static getInstance(): EventCenter {
    if (!this.instance) {
      this.instance = new EventCenter();
    }
    return this.instance;
  }

  init() {
    if (this.state !== STATE.SLEEPING) {
      return;
    }
    super.init();

    events.on(ModelEventType.SwitchTheme, this.modelThemeChanged.bind(this));
    events.on(ModelEventType.SetPicked, this.modelPickChanged.bind(this));
  }

  // 暂时关闭事件中心
  sleep() {
    super.sleep();

    events.off(ModelEventType.SwitchTheme);
    events.off(ModelEventType.SetPicked);

    // 清除已选中的模型
    clearSelectedMeshes();
  }

  get pickType() {
    return this._pickType;
  }

  // 设置拾取类型
  setPickType(type: number[], clear: boolean = true) {
    if (!isEqual(this._pickType, type)) {
      this._pickType = type;
      if (clear) {
        // 切换拾取类型，需要清除已选中的模型
        clearSelectedMeshes();
      }
    }
    return this;
  }

  /**
   * 获取当前拾取模式,几何/网格
   */
  get pickMode() {
    return this._pickMode;
  }

  /**
   * 设置拾取模式,用于切换几何/网格的拾取
   */
  set pickMode(mode: 'geometry' | 'mesh') {
    this._pickMode = mode;
  }

  /**
   * 模型主题发生变化，主要改变选取模型的颜色
   * @param modelTheme 新的主题
   */
  modelThemeChanged = (modelTheme: ModelTheme) => {
    this.currentModelTheme = modelTheme;
  };

  /**
   * 已选中的模型发生变化
   * @param modelPick
   */
  modelPickChanged = (modelPick: ModelPickEvent) => {
    selectMeshes(
      modelPick.indices,
      modelPick.theme,
      this.currentModelTheme === ModelTheme.Default,
    );
  };

  onCanvasPointerDown(ev: EventsRes<MouseEvent>): void {
    this.picker.setPointerDownPos(ev);
    if (ev.button.onRight) {
      this.isMouseRightMoving = false;
      this.rightButtonDownMouse = ev.mouse;
    }
  }

  onCanvasPointerup(ev: EventsRes<PointerEvent>) {
    const { event, button } = ev;

    if (this.state === STATE.DEFAULT) {
      if (this.idsMap?.size > 0) {
        if (button.onLeft) {
          const selected = this.picker.select2();
          const ids = handleSelect(selected, this.currentModelTheme);
          if (ids.length > 0) {
            events.emit(ModelEventType.Pick, {
              indices: ids,
              selected: true,
            } as ModelPickEvent);
          }
        }
      } else {
        // 鼠标右键不取消选中模型
        if (!button.onRight) {
          clearSelectedMeshes();
        }
      }
      if (button.onRight && !this.isMouseRightMoving) {
        userEvents.emit(CMEVENTS.MODEL_RIGHT_CLICK, {
          event,
          data: getAllSelectedMeshesId(),
        });
      }
    }
    this.idsMap = null;
  }

  onCanvasPointerMove(ev: EventsRes<MouseEvent>) {
    const { button } = ev;

    if (button.onRight && !this.isMouseRightMoving) {
      const { x, y } = this.rightButtonDownMouse;
      const dx = Math.abs(ev.mouse.x - x);
      const dy = Math.abs(ev.mouse.y - y);
      if (dx > 3 || dy > 3) {
        this.isMouseRightMoving = true;
      }
    }
    // 拾取
    if (this.pickingData.pixelBuffer && !button.buttonDown) {
      this.idsMap = this.mouseMoving(this.mouse);
    }

    if (this.state === STATE.DEFAULT && !button.buttonDown) {
      MouseStyle.setName('');

      const pickSet = this._pickType.reduce((set, type) => {
        return { ...set, ...pickSetting[type] };
      }, {});
      const dxids =
        this._pickMode === 'geometry'
          ? documentManager.getGeometriesId()
          : documentManager.getMeshesId();
      if (dxids.length === 0) {
        // SDK 如果 pickable dxids 为空,则能拾取所有的,实际上我们期望的是所有的都不能拾取,所以这里直接return
        return;
      }
      this.picker.pick(ev, pickSet, { pickable: { dxids, pickable: true } });
    }
  }

  mouseMoving(mouse: MouseInfo) {
    const mouseX = mouse.x;
    const mouseY = mouse.y;
    const idMap = new Map();
    const setId = (id: number) => {
      if (!idMap.has(id)) {
        idMap.set(id, 1);
      } else {
        const t = idMap.get(id);
        idMap.set(id, t + 1);
      }
    };
    // TODO 可以使用 renderer.readRenderTargetPixelsAsync(pickingTexture, 0, 0, 5, 5, pixelBuffer)
    // 读取渲染目标的像素值，就不需要使用循环
    const threshold = this.threshold || 2;
    for (let x = mouseX - threshold; x < mouseX + threshold; x++) {
      for (let y = mouseY - threshold; y < mouseY + threshold; y++) {
        const i =
          Math.round(
            x + (this.canvas.clientHeight - y) * this.canvas.clientWidth,
          ) * 4; // 获取像素点index
        const id =
          (this.pickingData.pixelBuffer[i] << 16) |
          (this.pickingData.pixelBuffer[i + 1] << 8) |
          this.pickingData.pixelBuffer[i + 2];
        // TODO 应该是4个通道，这里少用了一个Alpha，就导致能表示的范围就小了
        // 在进行网格拾取的时候，id就是网格单元的id
        if (id !== 0) {
          setId(id);
        }
      }
    }
    return idMap.size > 0 ? idMap : null;
  }

  //*****pointerMove end */
  /**
   *
   * offCavasEvent
   */
  offCanvasPointerUp(event: PointerEvent) {
    if (event.target === this.sceneSetup.domElement().childNodes[1]) {
      return;
    }
    event.preventDefault();
    event.stopPropagation();
    // TODO 结束框选
  }

  setState(state: string) {
    if (state === this.state) {
      return this;
    }

    if (state !== STATE.DEFAULT) {
      this.picker.setState(PickerState.onCommand);
    }
    this.touchExit();
    this.state = state;
    if (state === 'editGroup') this.editingGroup = true;
    return this;
  }

  setDefault(force: boolean = false) {
    this.picker.setState(PickerState.default);
    this.setThreshold(null);
    if (force) {
      this.state = STATE.DEFAULT;
      this.editingGroup = false;
    } else {
      if (this.editingGroup) {
        this.state = 'editGroup';
      } else {
        this.state = STATE.DEFAULT;
      }
    }
    this.clearExit();
    return this;
  }
}

export const nextmeshEventCenter = () => {
  return EventCenter.getInstance();
};
